#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>


static struct class *second_cls;
static struct class_device *second_cls_dev;

static volatile unsigned long *gpfcon;
static volatile unsigned long *gpfdat;

static volatile unsigned long *gpgcon;
static volatile unsigned long *gpgdat;

/* GPF0 GPF2 GPG3 GPG11 */
static int second_drv_open(struct inode *inode, struct file *file)
{
	*gpfcon &= ~((3<<0) | (3<<4));
	
	*gpgcon &= ~((3<<6) | (3<<22));
	return 0;
}

static ssize_t second_drv_read(struct file *file, __user char *buf, size_t count, loff_t *ppos)
{
	unsigned char keyvals[4];
	unsigned int val;

	if(count != sizeof(keyvals))
		return -EINVAL;

	val = *gpfdat;
	keyvals[0] = (val & (1<<0)) ? 1 : 0;
	keyvals[1] = (val & (1<<2)) ? 1 : 0;

	val = *gpgdat;
	keyvals[2] = (val & (1<<3)) ? 1 : 0;
	keyvals[3] = (val & (1<<11)) ? 1 : 0;

	copy_to_user(buf, keyvals, sizeof(keyvals));

	return sizeof(keyvals);
}

static struct file_operations second_drv_fops = {
	.owner = THIS_MODULE,
	.open  = second_drv_open,
	.read  = second_drv_read,
};

int major;
static int second_drv_init(void)
{
	major = register_chrdev(0, "second_drv", &second_drv_fops);

	second_cls = class_create(THIS_MODULE, "second_drv");

	second_cls_dev = class_device_create(second_cls, NULL, MKDEV(major, 0), NULL, "second_drv");

	gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
	gpfdat = gpfcon + 1;

	gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
	gpgdat = gpgcon + 1;	
	return 0;
}

static void second_drv_exit(void)
{
	unregister_chrdev(major, "second_drv");
	class_device_unregister(second_cls);
	class_destroy(second_cls);
	iounmap(gpfcon);
	iounmap(gpgcon);
}

module_init(second_drv_init);
module_exit(second_drv_exit);
MODULE_LICENSE("GPL");


